﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using System.IO;
using System;
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using XfTechOAWeb.Data.Base;
using XfTechOAWeb.EFCore.Base;
using XfTechOAWeb.EFCore;
using XfTechOAWeb.Infrastructure.Utilities;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using XfTechOAWeb.Infrastructure.JWT;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Authorization;
using XfTechOAWeb.ApiServer.Auth;

namespace XfTechOAWeb.ApiServer.ServiceExtensions
{
    /// <summary>
    /// 扩展方法怎么写？  -- 静态的类，静态的方法，第一个参数 this开头的，this后面跟上一个类型的名称
    /// </summary>
    public static class ServicesSetupExt
    {
        /// <summary>
        /// 配置数据库上下文
        /// </summary>
        /// <param name="services"></param>
        public static void AddDbSetup(this IServiceCollection services)
        {
            //注册DB上下文服务
            string strDbType = AppConfigurtaionServices.Get("SqlType"); //读取配置
            if (strDbType == "MySql")
            {
                //注册上下文
                services.AddDbContext<DbContext, MySqlDbContext>();
            }
            else if (strDbType == "SqlServer")
            {
                //注册上下文
                services.AddDbContext<DbContext, SqlServerDbContext>();
            }
            //注册工作单元
            services.AddScoped<IUnitOfWork, UnitOfWork>();
            services.AddScoped<IUnitOfWorkManage, UnitOfWorkManage>();
        }

        /// <summary>
        /// 配置跨域服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="cors"></param>
        public static void AddCorsSetup(this IServiceCollection services, string[] cors)
        {
            services.AddCors(opt =>
            {
                //添加默认的跨域策略
                //opt.AddDefaultPolicy(p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());//AllowAnyOrigin允许所有的原地址跨域访问，安全性较差

                //读取配置文件中的CorsIps字符串     "http://localhost:8081,http://localhost:8080,http://localhost:1234"
                //string[] cors = Configuration["CorsIps"].Split(',');

                //默认策略
                opt.AddDefaultPolicy(p => p.WithOrigins(cors)
                                           .AllowAnyMethod()
                                           .AllowAnyHeader()
                );

                //命名策略
                opt.AddPolicy("跨域策略1", p => p.WithOrigins(cors)
                                           .AllowAnyMethod()
                                           .AllowAnyHeader()
                );

            });
        }


        /// <summary>
        /// 配置Swagger服务
        /// </summary>
        /// <param name="services"></param>
        public static void AddSwaggerSetup(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                //var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);  //获取应用程序的运行目录
                //获取应用程序所在的绝对路径
                var basePath = AppContext.BaseDirectory;
                //动态获取xml文件的名称
                var xmlfile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                //拼接XML文件所在路径
                var xmlPath = Path.Combine(basePath, xmlfile);
                //让Swagger显示方法、类的XML注释信息
                c.IncludeXmlComments(xmlPath, true);

                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "XfTechOAWeb",
                    Version = "v1",
                    Description = "智慧低代码平台",                //描述信息
                    Contact = new OpenApiContact()                //开发者信息
                    {
                        Name = "雪人王",
                        Email = "99825949@qq.com",
                        Url = new Uri("https://gitee.com/xuerenwang")
                    }
                });

                //开启Authorize权限按钮
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {
                    Description = "这是方式一(直接在输入框中输入认证信息，不需要在开头添加Bearer)",
                    Name = "Authorization",         //请求头 属性名
                    In = ParameterLocation.Header,  //jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.Http,
                    Scheme = "Bearer",
                    BearerFormat = "JWT"
                });
                //注册全局认证（所有的接口都可以使用认证）
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme{
                        Reference = new OpenApiReference {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        }
                        },new string[] { }
                    }
                });
            });
        }

        /// <summary>
        /// 配置认证服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="Configuration"></param>
        public static void AddAuthenticationSetup(this IServiceCollection services, IConfiguration Configuration)
        {
            //读出appsettings.json中JWTToken配置并与JWTTokenOptions绑定
            JWTTokenOptions JWTTokenOptions = new JWTTokenOptions();
            Configuration.Bind("JWTToken", JWTTokenOptions);

            //配置JwtBearer身份认证服务
            services.AddAuthentication(option =>
            {
                //认证模式
                option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                //质询模式
                option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(option =>
            {
                option.RequireHttpsMetadata = false;//设置元数据地址或权限是否需要HTTP
                option.SaveToken = true;
                //Token验证参数
                option.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(JWTTokenOptions.Secret)),
                    ValidIssuer = JWTTokenOptions.Issuer,
                    ValidAudience = JWTTokenOptions.Audience,
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ClockSkew = TimeSpan.Zero,
                    ValidateLifetime = true
                };
                //如果jwt过期，在返回的header中加入Token-Expired字段为true，前端在获取返回header时判断
                option.Events = new JwtBearerEvents()
                {
                    OnAuthenticationFailed = context =>
                    {
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }
                };
            });

            //读配置方法一
            //JWTTokenOptions JWTTokenOptions = Configuration.GetSection("JWTToken").Get<JWTTokenOptions>();
            //services.AddSingleton<JWTTokenOptions>();

            //读配置方法二，并注册IOptions<JWTTokenOptions>服务
            services.Configure<JWTTokenOptions>(Configuration.GetSection("JWTToken"));

            //注册JWT令牌生成 帮助类
            services.AddSingleton<JwtTokenHelper>();
        }

        /// <summary>
        /// 配置授权服务
        /// </summary>
        /// <param name="services"></param>
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            services.AddAuthorization(options =>
            {
                //基于策略的授权
                //options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
                //options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
                options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));
                //添加自定义策略授权
                //options.AddPolicy("Permission", policy => policy.Requirements.Add(new PermissionAuthorizationRequirement()));
            });
            services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>(); //依赖注入

        }
    }
}
